// 给定一个链表的头节点  head ，返回链表开始入环的第一个节点。 如果链表无环，则返回 null。

// 如果链表中有某个节点，可以通过连续跟踪 next 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置（索引从 0 开始）。如果 pos 是 -1，则在该链表中没有环。注意：pos 不作为参数进行传递，仅仅是为了标识链表的实际情况。

// 不允许修改 链表。

// 输入：head = [3,2,0,-4], pos = 1
// 输出：返回索引为 1 的链表节点
// 解释：链表中有一个环，其尾部连接到第二个节点。
// 示例 2：



// 输入：head = [1,2], pos = 0
// 输出：返回索引为 0 的链表节点
// 解释：链表中有一个环，其尾部连接到第一个节点。
// 示例 3：



// 输入：head = [1], pos = -1
// 输出：返回 null
// 解释：链表中没有环。

// 方法一：哈希表
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
 var detectCycle = function(head) {
  if(head == null){
      return null
  }
  let arr = new Set()
  while(head != null){
      if(arr.has(head)){
          return head
      }
      arr.add(head)
      head = head.next
  }
  return null
};

// 方法二：快慢指针
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
 var detectCycle = function(head) {
  if (head == null || head.next == null) {
      return null
  }
  let fast = head
  let slow = head
  while(fast !== null){
      slow = slow.next
      if(fast.next !== null){
          fast = fast.next.next
      }else{
          return null
      }
      if(fast == slow){
          let pre = head
          while(slow !== pre){
              pre = pre.next
              slow = slow.next
          }
          return pre
      }
  }
  return null
};
// 复盘：
// 我们使用两个指针，fast 与 slow。它们起始都位于链表的头部。随后，slow 指针每次向后移动一个位置，而 fast 指针向后移动两个位置。
// 如果链表中存在环，则 fast 指针最终将再次与 slow 指针在环中相遇。

// 设链表中环外部分的长度为 a。slow 指针进入环后，又走了 b 的距离与 fast 相遇。
// 此时，fast 指针已经走完了环的 n 圈，因此它走过的总距离为 a+n(b+c)+b=a+(n+1)b+nc

// 根据题意，任意时刻，fast 指针走过的距离都为 slow 指针的 2 倍。因此，我们有
// a+(n+1)b+nc=2(a+b) \implies a=c+(n-1)(b+c)
// a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c)

// 有了 a=c+(n-1)(b+c) 的等量关系，我们会发现：从相遇点到入环点的距离加上 n-1 圈的环长，恰好等于从链表头部到入环点的距离。

// 因此，当发现 slow 与 fast 相遇时，我们再额外使用一个指针 tr。起始，它指向链表头部；随后，它和 slow 每次向后移动一个位置。最终，它们会在入环点相遇。
